package services;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.google.android.maps.GeoPoint;
import com.rentapark.app.MainScreen;
import com.rentapark.app.R;
import com.rentapark.app.SearchScreen;
import data.Coordinate;
import data.DB;
import data.ParkingSpot;
import data.ParkingSpotList;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.app.Dialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.util.Log;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;

/*this service is used when a user is seaking a parking spot to park
 * the service sends an http post message to a servlet giving the user's location
 * and the server responds with all the relevant parking spots that are close to the user's location
 */
public class SearchService extends Service implements LocationListener{
	private NotificationManager notificationMgr;
	private boolean runningFlag = false;
	int counter=0;
	DB parking_db;
	LocationManager manager;
	GeoPoint currentPoint;
	GeoPoint myLoc;
	String towers;
	Dialog progressDialog;
	String RspType="";
	Double latitude;
	Double longitude;
	public static final String TAG = "Rent-A-Park";
//this method handles the server's response which contains an xml with all the parking spots
	//all the parking spots and their data are save in the local DB
	private final Handler handler = new Handler() {  

		public void handleMessage(Message msg) {
			String result = msg.getData().getString("RESPONSE"); 
			String Reason="";
			Log.d("searchService","handler");
			parking_db=DB.getInstance();
			parking_db.dealClosed=false;
			//parsing the xml
			try {

				DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
				DocumentBuilder db = dbf.newDocumentBuilder();
				Document doc = db.parse(new InputSource(new StringReader(result)));
				NodeList nodeList = doc.getElementsByTagName("ParkingSpot");
				parking_db.dbList=new ParkingSpotList();
				if(nodeList!=null && nodeList.getLength()>0)
				{
					//filling the parking spots list
					for(int i = 0 ; i < nodeList.getLength();i++)
					{
						Element el = (Element)nodeList.item(i);
						longitude=getDoubleValue(el,"Longitud");
						latitude= getDoubleValue(el,"Latitud");
						int spotId=getIntegerValue(el,"SpotID");
						String ttA=getTextValue(el,"timeToAvailable");
						int cell=getIntegerValue(el,"CellID");
						double owner=getDoubleValue(el,"owner_id");
						int prize=getIntegerValue(el, "prize");
						String ownerName=getTextValue(el,"ownerName");
						int ownerGrade=getIntegerValue(el,"ownerGrade");
						int status=getIntegerValue(el,"status");
						String com=getTextValue(el, "comment");
						Coordinate cord=new Coordinate(longitude,latitude);
						ParkingSpot spot=new ParkingSpot(cord,cell, ttA, owner,prize,com,spotId);
						spot.ownerName=ownerName;
						spot.status=status;
						spot.ownerGrade=ownerGrade;
						parking_db.dbList.add(spot);



					}
					Log.d("Service","vector is full- turn off service!!!!");



				}					
				runningFlag = false;
				Intent dialogIntent = new Intent(getBaseContext(), SearchScreen.class);
				dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				getApplication().startActivity(dialogIntent);

				SearchService.this.stopSelf();


			} 
			catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SAXException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}


		} 
	};

//onBind
	public IBinder onBind(Intent arg0) {
		Log.d("Service","onBind");

		return null;
	}
	//onCreate
	public void onCreate() {
		Log.d("Service","onCreate");

		notificationMgr =(NotificationManager)getSystemService(
				NOTIFICATION_SERVICE);
		manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
		manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f, (LocationListener) this);
		parking_db=DB.getInstance();
		displayNotificationMessage("starting Background Service");
	}
	//onDestroy
	public void onDestroy() {
		// TODO Auto-generated method stub
		Log.d("Service","onDestroy");
		runningFlag=false;
		super.onDestroy();
	}
	//onStart
	public void onStart(Intent intent, int startId) {
		// TODO Auto-generated method stub
		Log.d("Service","onStart");
		parking_db=DB.getInstance();
		super.onStart(intent, startId);
		if(runningFlag==false)
		{
			runningFlag = true;
			Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
			//gps settings for getting the user's location
			Criteria crit =new Criteria(); //get best deafult critiria (GPS/cellular/Wi-Fi)
			towers= manager.getBestProvider(crit, false); //best reception/power re/ things like that
			Location loc = manager.getLastKnownLocation(towers);	//get your location
			Log.d("test",loc.toString());
			
			Log.d("test",Double.toString((loc.getLatitude())));
			if(loc!=null)
			{
				parking_db.curLocLat=loc.getLatitude();
				parking_db.curLocLong =loc.getLongitude();
				Log.d("service- latitud",Double.toString(loc.getLatitude()));
				Log.d("service- latitud",Double.toString(loc.getLongitude()));
			}
			thr.start();
		}

	}
	//onUnBind
	public boolean onUnbind(Intent intent) {
		// TODO Auto-generated method stub
		Log.d("Service","onUnbind");
		//Toast.makeText(this, "MyAlarmService.onUnbind()", Toast.LENGTH_LONG).show();
		return super.onUnbind(intent);
	}
//method for displaying service's notficiation in notification bar
	private void displayNotificationMessage(String message)
	{
		Notification notification = new Notification(R.drawable.alert,
				message,System.currentTimeMillis());
		PendingIntent contentIntent =
				PendingIntent.getActivity(this, 0,new Intent(this, MainScreen.class), 0);
		notification.setLatestEventInfo(this, "Rent-A-Park",message,
				contentIntent);
		notificationMgr.notify(R.string.app_notification_id, notification);
	}
	/*this inner class sends the http post (that contains an xml with data 
	 * about the user's location) to the server
	 */
	class ServiceWorker implements Runnable
	{
		final ResponseHandler<String> responseHandler = new ResponseHandler<String>() {   
			public String handleResponse(HttpResponse response) {    

				HttpEntity entity = response.getEntity();   
				Log.d("service","runn");
				String result = null; 
				try { 
					result = data.CommonUtilities.inputStreamToString(entity.getContent());   
					Message message = new Message();     
					Bundle bundle = new Bundle();         
					bundle.putString("RESPONSE", result); 
					message.setData(bundle); 
					handler.sendMessage(message);         
				} catch (IOException e) { 
					Log.e("Class6",  " ", e); 
				} 
				return result; 
			} 
		}; 
		public void run() {
			 
			if (runningFlag){

				Log.d(SearchService.TAG, "service processing");
				HttpClient httpclient = new DefaultHttpClient();
				parking_db=DB.getInstance();
				String url="http://";
				url+=parking_db.instanceDNS;
				url+=":8080/ParkAndLetPark/ParkingsSearch";
				Log.d("url is",url);
				HttpPost httppost = new HttpPost(url);
				//building the xml
				try {
					try{
						DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();

						DocumentBuilder docBuilder = builderFactory.newDocumentBuilder();

						//creating a new instance of a DOM to build a DOM tree.
						Document doc = docBuilder.newDocument();
						Element Request = doc.createElement("MSG_TYPE");
						Request.appendChild(doc.createTextNode("PARK_REQUEST"));
						doc.appendChild(Request);

						Element Userid=doc.createElement("USER_ID");
						Userid.appendChild(doc.createTextNode(Double.toString(parking_db.userID)));//can be 0 on newUser!!
						Request.appendChild(Userid);

						Element longi=doc.createElement("LONGI");
						Element lati=doc.createElement("LAT");

						longi.appendChild(doc.createTextNode(Double.toString(parking_db.curLocLong)));
						lati.appendChild(doc.createTextNode(Double.toString(parking_db.curLocLat)));

						Userid.appendChild(longi);
						longi.appendChild(lati);

						TransformerFactory factory = TransformerFactory.newInstance();
						Transformer transformer = factory.newTransformer();

						transformer.setOutputProperty(OutputKeys.INDENT, "yes");

						StringWriter sw = new StringWriter();
						StreamResult result = new StreamResult(sw);
						DOMSource source = new DOMSource(doc);
						transformer.transform(source, result);
						String xmlString = sw.toString();
						Log.d("xmlString","^^^^^^"+xmlString);


						StringEntity se = new StringEntity(xmlString); //XML as a string
						se.setContentType("text/xml"); //declare it as XML
						httppost.setEntity(se);

						String response = httpclient.execute(httppost,responseHandler);
						Log.d("Service","Response* "+response);
					}
					catch (ClientProtocolException e) {
						Log.e("LOGTAG", " " , e); 
					} catch (IOException e) {
						Log.e("LOGTAG", " " , e); 
					}

				}
				catch(Exception e)
				{
					Log.e("LOGTAG", " " , e); 
				}
			}
		}
	}
//this method is used to parse the xml: get a string value
	private String getTextValue(Element ele, String tagName) {
		String textVal = null;
		NodeList nl = ele.getElementsByTagName(tagName);
		if(nl != null && nl.getLength() > 0) {
			Element el = (Element)nl.item(0);
			textVal = el.getFirstChild().getNodeValue();
		}

		return textVal;
	}
	//this method is used to parse the xml: get a double value
	private double getDoubleValue(Element ele, String tagName) {
		String strVal = null;
		double doubleVal=0;
		NodeList nl = ele.getElementsByTagName(tagName);
		if(nl != null && nl.getLength() > 0) {
			Element el = (Element)nl.item(0);
			strVal = el.getFirstChild().getNodeValue();
			doubleVal=Double.parseDouble(strVal);
		}

		return doubleVal;
	}
	//this method is used to parse the xml: get an integer value
	private int getIntegerValue(Element ele, String tagName) {
		String strVal = null;
		int intVal=0;
		NodeList nl = ele.getElementsByTagName(tagName);
		if(nl != null && nl.getLength() > 0) {
			Element el = (Element)nl.item(0);
			strVal = el.getFirstChild().getNodeValue();
			intVal=Integer.parseInt(strVal);
		}

		return intVal;
	}

	//onLocationChanged method: updates user location
	public void onLocationChanged(Location location) {

		if (location != null) {
			parking_db.curLocLat=location.getLatitude();
			parking_db.curLocLong=location.getLongitude();
	}
		
	}
	//onProviderDisabled: method to override (GPS)
	public void onProviderDisabled(String provider) {
		// TODO Auto-generated method stub
		
	}
	//onProviderEnabled: method to override (GPS)
	public void onProviderEnabled(String provider) {
		// TODO Auto-generated method stub
		
	}
	//onStatusChange: method to override (GPS)
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// TODO Auto-generated method stub
		
	}




}
